package com.uam.core.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.uam.core.entity.uitls.CurrentListGroup;
import com.uam.core.entity.uitls.ZipUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.uam.core.dao.elasticsearch.ElasticsearchDao;
import com.uam.core.dao.mysql.AircraftDao;
import com.uam.core.dao.mysql.TaskDao;
import com.uam.core.entity.constant.Constant;
import com.uam.core.entity.enums.BaseStationTypes;
import com.uam.core.entity.enums.ElasticsearchIndices;
import com.uam.core.entity.model.AircraftModel;
import com.uam.core.entity.model.ElasticsearchQueryResult;
import com.uam.core.entity.model.ElasticsearchQueryResult.CommonFields;
import com.uam.core.entity.model.ElasticsearchQueryResult.RouteComponentFields;
import com.uam.core.entity.model.PointDetail;
import com.uam.core.entity.model.TaskModel;
import com.uam.core.entity.model.TaskQueryResult;
import com.uam.core.entity.model.TaskTrackDetail;
import com.uam.core.entity.model.TopTracks;
import com.uam.core.entity.model.TrackPoint;
import com.uam.core.entity.model.TrackPositionDetail;
import com.uam.core.entity.uitls.SpatialUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 轨迹管理
 *
 * @author lishf
 */
@Service
@Slf4j
public class TrackService {

	@Autowired
	private TaskDao taskDao = null;

	@Autowired
	private AircraftDao aircraftDao = null;

	@Autowired
	private ElasticsearchDao elasticsearchDao = null;

	@Value("${date.format}")
	private String dateFormat = null;

	@Value("${track.top.size}")
	private int topSize = 0;

	@Value("${track.detail.mode}")
	private boolean trackDetailMode = false;

	@Value("${track.conflict.time.buffer.mode}")
	private boolean timeBufferMode = false;

	@Value("${track.conflict.time.buffer.num}")
	private int timeBufferNum = 0;

	@Value("${track.conflict.time.buffer.seconds}")
	private int timeBuffer = 0;

	public TaskTrackDetail getTaskTrackDetail(int taskId) {
		if (taskId == -1) {
			return null;
		}
		try {
			List<TrackPoint> track = null;
			List<TaskTrackDetail> conflictTasks = null;
			TaskModel task = this.taskDao.detailTask(taskId).getData().get(0);
			int aircraftId = task.getAircraftId();
			AircraftModel aircraft = this.aircraftDao.detailAircraft(aircraftId).getData().get(0);
			JSONArray settings = JSON.parseArray(task.getSettings());
			TrackDetail trackDetail = this.getTrack(taskId,
					QueryBuilders.termQuery(CommonFields.TASK_ID.getName(), String.valueOf(taskId)),
					SortBuilders.fieldSort(RouteComponentFields.OWN_TIME.getName()).order(SortOrder.ASC), true);
			if (trackDetail != null) {
				track = trackDetail.getTrack();
				conflictTasks = trackDetail.getConflictTasks();
			}
			double distance = task.getActualDistance();
			if (distance <= 0.00D) {
				distance = task.getPredictDistance();
			}
			double cost = task.getActualCost();
			if (cost <= 0.00D) {
				cost = task.getPredictCost();
			}
			TaskTrackDetail detail= new TaskTrackDetail(taskId, task.getName(), (JSONObject) settings.remove(0),
					(JSONObject) settings.remove(settings.size() - 1), settings, task.getStatus(), task.getMode(),
					distance, cost, aircraftId, aircraft.getName(), aircraft.getMinAltitude(),
					aircraft.getMaxAltitude(), aircraft.getMaxSpeed(), aircraft.getMaxDuration(),
					task.getStartTime().getTime() / 1000L, aircraft.getSpeed(), aircraft.getModelName(),
					task.getAuthorId(), task.getAuthorName(), track, conflictTasks);
			String points=task.getTrackPoints();

			if( StringUtils.isNotBlank(points)){
				detail.setTrackInfo(JSONArray.parseArray(ZipUtil.uncompressBase64(points)));
			}

			detail.setRectanglePoint(task.getRectanglePoint());
			if(StringUtils.isNotBlank(task.getRectanglePoint()) ){
				detail.setAreaPointVo(CurrentListGroup.isInRectangle(task,detail.getTrack()));
			}

			return detail;
		} catch (Throwable e) {
			TrackService.log.error(e.getMessage(), e);
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	private TrackDetail getTrack(int taskId, QueryBuilder query, SortBuilder<?> sort, boolean needConflict) {
		ElasticsearchQueryResult trackResult = this.elasticsearchDao.query(query, 1, 10000, sort, new String[] {
				CommonFields.POSITION.getName(), CommonFields.ALTITUDE.getName(),
				RouteComponentFields.OWN_TIME.getName(), RouteComponentFields.SPEED.getName(),
				RouteComponentFields.SAFE_DISTANCE.getName(), RouteComponentFields.COMMUNICATION_SIGNAL.getName(),
				RouteComponentFields.NAVIGATION_SIGNAL.getName(), RouteComponentFields.SUPERVISORY_SIGNAL.getName(),
				RouteComponentFields.POSITIONING_ACCURACY.getName(), RouteComponentFields.CONN_NUM.getName(),
				RouteComponentFields.COMMUNICATION_SIGNAL_NUM.getName(),
				RouteComponentFields.NAVIGATION_SIGNAL_NUM.getName(),
				RouteComponentFields.SUPERVISORY_SIGNAL_NUM.getName(), RouteComponentFields.CONFLICT_TASK_ID.getName(),
				RouteComponentFields.ACCELERATION.getName(), RouteComponentFields.RETARD_DISTANCE.getName(),
				RouteComponentFields.INTERSECTION_DISTANCE.getName(), RouteComponentFields.HOVER_COST.getName(),
				RouteComponentFields.COMMUNICATION_SIGNAL_POSITION.getName(),
				RouteComponentFields.NAVIGATION_SIGNAL_POSITION.getName(),
				RouteComponentFields.SUPERVISORY_SIGNAL_POSITION.getName() },
				new String[] { CommonFields.TASK_ID.getName(), RouteComponentFields.NEXT_POSITION_ID.getName(),
						RouteComponentFields.NEXT_POSITION_DISTANCE.getName(),
						RouteComponentFields.NEXT_POSITION_COST.getName(),
						RouteComponentFields.LAST_POSITION_ID.getName(),
						RouteComponentFields.LAST_POSITION_DISTANCE.getName(),
						RouteComponentFields.LAST_POSITION_COST.getName(), RouteComponentFields.REMAINING.getName(),
						RouteComponentFields.POSITION_SHAPE.getName(), RouteComponentFields.IS_PIVOTAL.getName(),
						CommonFields.STATUS.getName() },
				ElasticsearchIndices.ROUTE_COMPONENT_INDEX);
		if (ElasticsearchQueryResult.EMPTY != trackResult) {
			int i = 0;
			long startTime = 0L;
			long endTime = 0L;
			List<Map<String, Object>> trackPoints = trackResult.getData();
			int size = trackPoints.size();
			List<TrackPoint> track = new ArrayList<TrackPoint>();
			Map<Integer, List<PointDetail>> conflictTaskPoints = new LinkedHashMap<Integer, List<PointDetail>>();
			while (i < size) {
				Map<String, Object> trackPoint = trackPoints.get(i++);
				long time = ((Long) trackPoint.remove(RouteComponentFields.OWN_TIME.getName())).longValue();
				if (i == 1) {
					if (!this.trackDetailMode) {
						startTime = time;
					}
				} else if (i == size) {
					if (!this.trackDetailMode) {
						endTime = time;
					}
				}
				Map<String, Object> pointPosition = (Map<String, Object>) trackPoint
						.remove(CommonFields.POSITION.getName());
				double safeDistance = ((Double) trackPoint.remove(RouteComponentFields.SAFE_DISTANCE.getName()))
						.doubleValue();
				Double positioningAccuracy = (Double) trackPoint
						.remove(RouteComponentFields.POSITIONING_ACCURACY.getName());
				Integer connNum = (Integer) trackPoint.remove(RouteComponentFields.CONN_NUM.getName());
				Double communicationSignal = (Double) trackPoint
						.remove(RouteComponentFields.COMMUNICATION_SIGNAL.getName());
				Double navigationSignal = (Double) trackPoint.remove(RouteComponentFields.NAVIGATION_SIGNAL.getName());
				Double supervisorySignal = (Double) trackPoint
						.remove(RouteComponentFields.SUPERVISORY_SIGNAL.getName());
				Integer communicationSignalNum = (Integer) trackPoint
						.remove(RouteComponentFields.COMMUNICATION_SIGNAL_NUM.getName());
				Integer navigationSignalNum = (Integer) trackPoint
						.remove(RouteComponentFields.NAVIGATION_SIGNAL_NUM.getName());
				Integer supervisorySignalNum = (Integer) trackPoint
						.remove(RouteComponentFields.SUPERVISORY_SIGNAL_NUM.getName());
				List<Integer> conflictTaskIds = (List<Integer>) trackPoint
						.remove(RouteComponentFields.CONFLICT_TASK_ID.getName());
				List<PointDetail> conflictPoints = needConflict ? this.generateConflictPoints(time, conflictTaskIds)
						: null;
				Double acceleration = (Double) trackPoint.remove(RouteComponentFields.ACCELERATION.getName());
				Double retardDistance = (Double) trackPoint.remove(RouteComponentFields.RETARD_DISTANCE.getName());
				if (retardDistance != null && retardDistance.doubleValue() < 0.00D) {
					retardDistance = null;
				}
				Double intersectionDistance = (Double) trackPoint
						.remove(RouteComponentFields.INTERSECTION_DISTANCE.getName());
				if (intersectionDistance != null && intersectionDistance.doubleValue() < 0.00D) {
					intersectionDistance = null;
				}
				Double hoverCost = (Double) trackPoint.remove(RouteComponentFields.HOVER_COST.getName());
				if (hoverCost != null && hoverCost.doubleValue() < 0.00D) {
					hoverCost = null;
				}
				if (acceleration != null && retardDistance == null && intersectionDistance == null
						&& hoverCost == null) {
					acceleration = null;
				}
				List<Double> communicationSignalPosition = (List<Double>) trackPoint
						.remove(RouteComponentFields.COMMUNICATION_SIGNAL_POSITION.getName());
				List<Double> navigationSignalPosition = (List<Double>) trackPoint
						.remove(RouteComponentFields.NAVIGATION_SIGNAL_POSITION.getName());
				List<Double> supervisorySignalPosition = (List<Double>) trackPoint
						.remove(RouteComponentFields.SUPERVISORY_SIGNAL_POSITION.getName());
				track.add(new TrackPoint((String) trackPoint.remove(CommonFields.ID.getName()), taskId,
						new double[] { ((Double) pointPosition.remove(CommonFields.LON.getName())).doubleValue(),
								((Double) pointPosition.remove(CommonFields.LAT.getName())).doubleValue() },
						time / 1000L, ((Double) trackPoint.remove(RouteComponentFields.SPEED.getName())).doubleValue(),
						((Double) trackPoint.remove(CommonFields.ALTITUDE.getName())).doubleValue(),
						communicationSignal != null ? communicationSignal.intValue() : -1,
						navigationSignal != null ? navigationSignal.intValue() : -1,
						supervisorySignal != null ? supervisorySignal.intValue() : -1, safeDistance,
						positioningAccuracy != null ? positioningAccuracy.doubleValue()
								: RouteService.NONE_SIGNAL_CONFIG.get(BaseStationTypes.COMMUNICATION).doubleValue()
										+ RouteService.NONE_SIGNAL_CONFIG.get(BaseStationTypes.NAVIGATION).doubleValue()
										+ RouteService.NONE_SIGNAL_CONFIG.get(BaseStationTypes.SUPERVISORY)
												.doubleValue()
										+ safeDistance,
						connNum != null ? connNum.intValue() : 0,
						communicationSignalNum != null ? communicationSignalNum.intValue() : -1,
						navigationSignalNum != null ? navigationSignalNum.intValue() : -1,
						supervisorySignalNum != null ? supervisorySignalNum.intValue() : -1, conflictTaskIds,
						conflictPoints != null && this.trackDetailMode ? conflictPoints : null,
						conflictTaskIds != null && conflictTaskIds.size() > 0, acceleration, retardDistance,
						intersectionDistance, hoverCost,
						communicationSignalPosition != null ? communicationSignalPosition : Constant.DOUBLE_LIST_EMPTY,
						navigationSignalPosition != null ? navigationSignalPosition : Constant.DOUBLE_LIST_EMPTY,
						supervisorySignalPosition != null ? supervisorySignalPosition : Constant.DOUBLE_LIST_EMPTY));
				if (!this.trackDetailMode && conflictPoints != null) {
					int j = 0;
					int tmpSize = conflictPoints.size();
					while (j < tmpSize) {
						PointDetail conflictPoint = conflictPoints.get(j++);
						Integer tmpTaskId = Integer.valueOf(conflictPoint.getTaskId());
						List<PointDetail> tmpConflictPoints = conflictTaskPoints.get(tmpTaskId);
						if (tmpConflictPoints == null) {
							tmpConflictPoints = new ArrayList<PointDetail>();
							conflictTaskPoints.put(tmpTaskId, tmpConflictPoints);
						}
						tmpConflictPoints.add(conflictPoint);
					}
				}
			}
			if (!this.trackDetailMode && conflictTaskPoints.size() > 0) {
				return new TrackDetail(track,
						this.generateConflictTasks(
								QueryBuilders.rangeQuery(RouteComponentFields.OWN_TIME.getName())
										.gte(Long.valueOf(startTime)).lte(Long.valueOf(endTime)),
								conflictTaskPoints.values()));
			}
			return new TrackDetail(track, null);
		}
		return null;
	}

	private List<TaskTrackDetail> generateConflictTasks(RangeQueryBuilder timeQuery,
			Collection<List<PointDetail>> conflictTaskPoints) {
		Iterator<List<PointDetail>> conflictTaskPointsIterator = conflictTaskPoints.iterator();
		List<TaskTrackDetail> conflictTasks = new ArrayList<TaskTrackDetail>(conflictTaskPoints.size());
		while (conflictTaskPointsIterator.hasNext()) {
			List<TrackPoint> track = null;
			List<PointDetail> conflictPoints = conflictTaskPointsIterator.next();
			PointDetail point = conflictPoints.get(0);
			int taskId = point.getTaskId();
			long startTime = point.getStartTime();
			double distance = 0.00D;
			double cost = 0.00D;
			BoolQueryBuilder query = QueryBuilders.boolQuery();
			query.filter(timeQuery);
			query.filter(QueryBuilders.termQuery(CommonFields.TASK_ID.getName(), String.valueOf(taskId)));
			TrackDetail trackDetail = this.getTrack(taskId, query,
					SortBuilders.fieldSort(RouteComponentFields.OWN_TIME.getName()).order(SortOrder.ASC), false);
			if (trackDetail != null) {
				track = trackDetail.getTrack();
				if (track != null) {
					int size = track.size();
					if (size > 0) {
						int i = 0;
						double maxDistance = Integer.MIN_VALUE;
						TrackPoint trackPoint = track.get(i++);
						startTime = trackPoint.getTime();
						cost = (track.get(size - 1).getTime() - startTime) / 60.00D;
						double[] position = trackPoint.getPosition();
						while (i < size) {
							double[] tmpPosition = track.get(i++).getPosition();
							double tmpDistance = SpatialUtil.computeDistance(position[0], position[1], tmpPosition[0],
									tmpPosition[1]);
							if (tmpDistance > maxDistance) {
								maxDistance = tmpDistance;
							}
							distance = tmpDistance + distance;
							position = tmpPosition;
						}
						i = 1;
						this.inferConflictPoint(point.getTime(), maxDistance, size, track);
						int num = conflictPoints.size();
						while (i < num) {
							this.inferConflictPoint(conflictPoints.get(i++).getTime(), maxDistance, size, track);
						}
					}
				}
			}
			conflictTasks.add(new TaskTrackDetail(taskId, point.getTaskName(), point.getStartPoint(),
					point.getEndPoint(), point.getPassPoints(), point.getStatus(), point.getMode(), distance, cost,
					point.getAircraftId(), point.getAircraftName(), point.getMinAltitude(), point.getMaxAltitude(),
					point.getMaxSpeed(), point.getMaxDuration(), startTime, point.getSpeed(), point.getModelName(),
					point.getAuthorId(), point.getAuthorName(), track, null));
		}
		return conflictTasks;
	}

	private void inferConflictPoint(long conflictTime, double maxDistance, int size, List<TrackPoint> track) {
		int i = 0;
		while (i < size) {
			TrackPoint trackPoint = track.get(i++);
			if (!trackPoint.isConflictPoint()) {
				double speed = trackPoint.getSpeed();
				trackPoint.setConflictPoint(
						speed > 0.00D && Math.abs(trackPoint.getTime() - conflictTime) <= (this.timeBufferMode
								? (int) ((maxDistance / (speed / 3.60D)) * this.timeBufferNum)
								: this.timeBuffer));
			}
		}
	}

	private List<PointDetail> generateConflictPoints(long time, List<Integer> conflictTaskIds) {
		if (conflictTaskIds == null) {
			return null;
		}
		int size = conflictTaskIds.size();
		if (size == 0) {
			return null;
		}
		int i = 0;
		List<PointDetail> pointDetails = new ArrayList<PointDetail>();
		while (i < size) {
			Integer conflictTaskId = conflictTaskIds.get(i++);
			if (conflictTaskId != null) {
				int conflictTaskIdValue = conflictTaskId.intValue();
				if (conflictTaskIdValue > -1) {
					pointDetails.add(this.position(conflictTaskIdValue, time, false));
				}
			}
		}
		if (pointDetails.size() == 0) {
			return null;
		}
		return pointDetails;
	}

	public TopTracks topTracks(int topSize) {
		TaskQueryResult taskResult = this.taskDao.queryTopTask();
		if (TaskQueryResult.EMPTY != taskResult) {
			if (topSize <= 0) {
				topSize = this.topSize;
			}
			int i = 0;
			int total = 0;
			List<List<TrackPoint>> tracks = new ArrayList<List<TrackPoint>>();
			List<TaskModel> tasks = taskResult.getData();
			int size = tasks.size();
			TermQueryBuilder extractQuery = QueryBuilders.termQuery(RouteComponentFields.IS_PIVOTAL.getName(), true);
			SortBuilder<?> sort = SortBuilders.fieldSort(RouteComponentFields.OWN_TIME.getName()).order(SortOrder.ASC);
			while (i < size) {
				int taskId = tasks.get(i++).getId();
				BoolQueryBuilder query = QueryBuilders.boolQuery();
				query.filter(extractQuery);
				query.filter(QueryBuilders.termQuery(CommonFields.TASK_ID.getName(), String.valueOf(taskId)));
				TrackDetail trackDetail = this.getTrack(taskId, query, sort, false);
				if (trackDetail != null) {
					List<TrackPoint> track = trackDetail.getTrack();
					if (track != null) {
						tracks.add(track);
						if (++total >= topSize) {
							break;
						}
					}
				}
			}
			return new TopTracks(total, tracks);
		}
		return TopTracks.EMPTY;
	}

	public TrackPositionDetail position(int taskId) {
		try {
			int index = 0;
			long currTime = this.position(taskId, System.currentTimeMillis(), true).getTime();
			double elapsedDistance = 0.00D;
			double elapsedCost = 0.00D;
			TaskTrackDetail taskTrackDetail = this.getTaskTrackDetail(taskId);
			List<TrackPoint> track = taskTrackDetail.getTrack();
			TrackPoint trackPoint = track.get(index);
			long time = trackPoint.getTime();
			if (currTime == time) {
				return new TrackPositionDetail(taskTrackDetail, index, elapsedDistance, elapsedCost);
			}
			int size = track.size();
			double[] position = trackPoint.getPosition();
			while (++index < size) {
				trackPoint = track.get(index);
				long tmpTime = trackPoint.getTime();
				elapsedCost = (tmpTime - time) + elapsedCost;
				time = tmpTime;
				double[] tmpPosition = trackPoint.getPosition();
				elapsedDistance = SpatialUtil.computeDistance(position[0], position[1], tmpPosition[0], tmpPosition[1])
						+ elapsedDistance;
				position = tmpPosition;
				if (currTime == time) {
					break;
				}
			}
			while (currTime == time && index + 1 < size) {
				trackPoint = track.get(++index);
				long tmpTime = trackPoint.getTime();
				elapsedCost = (tmpTime - time) + elapsedCost;
				time = tmpTime;
				double[] tmpPosition = trackPoint.getPosition();
				elapsedDistance = SpatialUtil.computeDistance(position[0], position[1], tmpPosition[0], tmpPosition[1])
						+ elapsedDistance;
				position = tmpPosition;
			}
			return new TrackPositionDetail(taskTrackDetail, index, elapsedDistance, elapsedCost / 60.00D);
		} catch (Throwable e) {
			TrackService.log.error(e.getMessage(), e);
			return null;
		}
	}

	private PointDetail position(int taskId, long currTime, boolean needConflict) {
		Long time = Long.valueOf(currTime);
		currTime = currTime / 1000L;
		TermQueryBuilder taskQuery = QueryBuilders.termQuery(CommonFields.TASK_ID.getName(), String.valueOf(taskId));
		BoolQueryBuilder query = QueryBuilders.boolQuery();
		query.filter(taskQuery);
		query.filter(QueryBuilders.rangeQuery(RouteComponentFields.OWN_TIME.getName()).gte(time));
		List<TrackPoint> forwardTrack = null;
		TrackDetail trackDetail = this.getTrack(taskId, query,
				SortBuilders.fieldSort(RouteComponentFields.OWN_TIME.getName()).order(SortOrder.ASC), needConflict);
		if (trackDetail != null) {
			forwardTrack = trackDetail.getTrack();
		}
		query = QueryBuilders.boolQuery();
		query.filter(taskQuery);
		query.filter(QueryBuilders.rangeQuery(RouteComponentFields.OWN_TIME.getName()).lt(time));
		List<TrackPoint> backwardTrack = null;
		trackDetail = this.getTrack(taskId, query,
				SortBuilders.fieldSort(RouteComponentFields.OWN_TIME.getName()).order(SortOrder.DESC), needConflict);
		if (trackDetail != null) {
			backwardTrack = trackDetail.getTrack();
		}
		if (forwardTrack != null) {
			TrackPoint forwardPoint = forwardTrack.get(0);
			if (backwardTrack != null) {
				TrackPoint backwardPoint = backwardTrack.get(0);
				if (forwardPoint.getTime() - currTime <= currTime - backwardPoint.getTime()) {
					return this.wrapPoint(taskId, forwardPoint);
				}
				return this.wrapPoint(taskId, backwardPoint);
			}
			return this.wrapPoint(taskId, forwardPoint);
		}
		return this.wrapPoint(taskId, backwardTrack.get(0));
	}

	private PointDetail wrapPoint(int taskId, TrackPoint point) {
		if (taskId == -1) {
			return null;
		}
		try {
			TaskModel task = this.taskDao.detailTask(taskId).getData().get(0);
			int aircraftId = task.getAircraftId();
			AircraftModel aircraft = this.aircraftDao.detailAircraft(aircraftId).getData().get(0);
			JSONArray settings = JSON.parseArray(task.getSettings());
			double distance = task.getActualDistance();
			if (distance <= 0.00D) {
				distance = task.getPredictDistance();
			}
			double cost = task.getActualCost();
			if (cost <= 0.00D) {
				cost = task.getPredictCost();
			}
			return new PointDetail(taskId, task.getName(), (JSONObject) settings.remove(0),
					(JSONObject) settings.remove(settings.size() - 1), settings, task.getStatus(), task.getMode(),
					distance, cost, aircraftId, aircraft.getName(), aircraft.getMinAltitude(),
					aircraft.getMaxAltitude(), aircraft.getMaxSpeed(), aircraft.getMaxDuration(),
					task.getStartTime().getTime() / 1000L, aircraft.getSpeed(), aircraft.getModelName(),
					task.getAuthorId(), task.getAuthorName(), point.getPosition(), point.getTime(), point.getSpeed(),
					point.getAltitude(), point.getCommunicationSignal(), point.getNavigationSignal(),
					point.getSupervisorySignal(), point.getSafeDistance(), point.getPositioningAccuracy(),
					point.getConnNum());
		} catch (Throwable e) {
			TrackService.log.error(e.getMessage(), e);
			return null;
		}
	}

	private class TrackDetail {

		private List<TrackPoint> track = null;

		private List<TaskTrackDetail> conflictTasks = null;

		public TrackDetail(List<TrackPoint> track, List<TaskTrackDetail> conflictTasks) {
			this.track = track;
			this.conflictTasks = conflictTasks;
		}

		public List<TrackPoint> getTrack() {
			return track;
		}

		public List<TaskTrackDetail> getConflictTasks() {
			return conflictTasks;
		}

	}
}
